Skip to content

Scheduler — Add hiddenDays option to hide arbitrary days of the week#33188

Open
aleksei-semikozov wants to merge 57 commits intoDevExpress:26_1from
aleksei-semikozov:feature/scheduler-hidden-days-impl-26_1
Open

Scheduler — Add hiddenDays option to hide arbitrary days of the week#33188
aleksei-semikozov wants to merge 57 commits intoDevExpress:26_1from
aleksei-semikozov:feature/scheduler-hidden-days-impl-26_1

Conversation

@aleksei-semikozov
Copy link
Copy Markdown
Contributor

No description provided.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review is ineligible. To be eligible to request a review, you need a paid Copilot license, or your organization must enable Copilot code review.

const normalizeView = (view: RawViewType): NormalizedView | undefined => (isObject(view)
? extend({}, DEFAULT_VIEW_OPTIONS[view.type as string], view) as NormalizedView
: DEFAULT_VIEW_OPTIONS[view]);
const normalizeView = (
Copy link
Copy Markdown
Contributor

@Tucchhaa Tucchhaa Apr 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think current logic to get normalized hiddenDays value is really over complicated.

I understand that existing mechanism (getViewOption) to get view option in scheduler isn't suitable, because if a view has a default value, then global value wouldn't apply. I think existing mechanism is very awkward and should be refactored.

But in the meantime, I think it is possible to greatly simplify the logic you've added. Here's how:

  1. add this code to scheduler_options_base_widget.ts:
getViewOption(optionName: string)
    if (optionName === 'hiddenDays') {
      return normalizeHiddenDaysViewOption(
        this.currentView?.type,
        this.currentView?.[optionName] ?? this.option(optionName)
      );
    }

    // ...
}
  1. Remove skipped days default values from DEFAULT_VIEW_OPTIONS

  2. Implement normalizeHiddenDaysViewOption:

const normalizeHiddenDaysViewOption = (view: ViewType, hiddenDays?: HiddenDays) => {
   const value = hiddenDays ? hiddenDays : defaultValueByView[view];
   
    // other checks and error logging

    return value;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if need to pass hiddenDays to somewhere, e.g. Header, then just pass it in the config, like 'currentDate' is passed:

private headerConfig(): {
   return {
       hiddenDays: this.getViewOption('hiddenDays')
       // ...
   }
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure this is a good idea.

It moves hiddenWeekDays normalization to getViewOption(), but that method works only for the current view. Because of that, NormalizedView would no longer be fully normalized, and DEFAULT_VIEW_OPTIONS would no longer be true internal defaults.

Also, the hidden days logic would be spread across different places instead of being resolved once in normalizeView(). So even if the current code is not perfect, this change would make the design less clear, not simpler.

currentDate is just one simple value, so it is easy to normalize in getViewOption().

hiddenWeekDays is more complex. Its final value depends on the view type, per-view value, global value, and default view settings. So it is better to resolve it in normalizeView(), where the view config is built.

@@ -0,0 +1,64 @@
export const isValidWeekday = (value: unknown): value is number => (
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor: now we have two names for the same entity: skippedDays and hiddenDays. I would suggest to only use one name in the codebase

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using skippedDays internally makes sense because skippedDays is a normalized value, while hiddenWeekDays is a public API option and may contain any user-provided input.

Comment thread packages/devextreme/js/__internal/scheduler/header/m_utils.ts
Comment thread packages/devextreme/js/__internal/scheduler/header/m_utils.ts Outdated
Comment thread packages/devextreme/js/__internal/scheduler/header/m_utils.ts Outdated
Comment thread packages/devextreme/js/__internal/scheduler/workspaces/m_timeline.ts Outdated
Comment on lines +45 to +54
get daysInInterval(): number {
if (this.skippedDays.length === 0) {
return this.baseDaysInInterval;
}
const visibleDayCount = 7 - this.skippedDays.length;
if (this.baseDaysInInterval >= 7) {
return visibleDayCount;
}
return this.baseDaysInInterval;
}
Copy link
Copy Markdown
Contributor

@Tucchhaa Tucchhaa Apr 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Basically what this getter does is:
if currentView is week or workWeek, then return 7 - skippedDays.length
else return 1

Can you simplify this getter to make it more clear?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Copy Markdown
Contributor

@Tucchhaa Tucchhaa Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a way to check if the currentView is week or workWeek without overriding baseDaysInInterval property in m_view_data_generator_week or m_view_data_generator_work_week?

I mean, something like:

const isWeekLikeView = this.viewType === 'week' || this.viewType === 'workWeek';

return isWeekLikeView
  ? 7 - this.skippedDays.length
   : 1;

Thus we wouldn't need baseDaysInInterval prop at all, because in all other viewDataGenerators apart from week don't override the value of baseDaysInInterval

return this.getFirstDayOfWeek(firstDayOfWeekOption) ?? 0;
}

protected getVisibleDayOffset(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this func can be private

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


constructor(public readonly viewType: ViewType) {}

get daysInInterval(): number {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add protected

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function is being used here /DevExtreme/packages/devextreme/js/__internal/scheduler/workspaces/m_timeline.ts (421,68):
Property 'daysInInterval' is protected and only accessible within class 'ViewDataGenerator' and its subclasses.

and in tests.

Cant make it protected or private

Comment on lines +107 to +109
public isSkippedDate(date: Date): boolean {
return isDateSkipped(date, this.skippedDays);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use the same name for the method:

public isDateSkipped(date: Date): boolean {
    return isDateSkipped(date, this.skippedDays);
  }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 40 out of 43 changed files in this pull request and generated 2 comments.

Comment thread packages/devextreme/js/ui/widget/ui.errors.js Outdated
Comment on lines +33 to +45
const resolveSkippedDays = (
viewType: ViewType,
perViewHiddenWeekDays: unknown,
globalHiddenWeekDays: number[] | undefined,
viewDefault: number[],
): number[] => {
const perView = normalizeHiddenWeekDays(perViewHiddenWeekDays);
if (perView !== undefined) {
return perView;
}
if (globalHiddenWeekDays !== undefined && VIEWS_SUPPORTING_HIDDEN_DAYS.has(viewType)) {
return normalizeHiddenWeekDays(globalHiddenWeekDays) ?? [];
}
Copy link

Copilot AI Apr 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolveSkippedDays calls normalizeHiddenWeekDays(globalHiddenWeekDays) for every view. When hiddenWeekDays contains all 7 days, this will log W1029 once per view, potentially spamming logs. Consider normalizing the global value once (and logging once) before mapping views, then reusing the normalized result for each view.

Copilot uses AI. Check for mistakes.
@Tucchhaa
Copy link
Copy Markdown
Contributor

Tucchhaa commented Apr 15, 2026

Day view Bug

  $('#scheduler').dxScheduler({
    timeZone: 'America/Los_Angeles',
    dataSource: data,
    views: ['day', 'week', 'workWeek', 'month', {
      type: 'day',
      name: 'myday',
      intervalCount: 7,
    }],
    hiddenWeekDays: [0, 1, 2, 3, 4, 5],
    currentView: 'myday',
    currentDate: new Date(2021, 3, 29),
    startDayHour: 9,
    height: 730,
  });

Actual result: all week days are visible

Expected result: hidden week days shouldn't be visible

Looks like we forgot about this case during the spec writing 😔

Copilot AI review requested due to automatic review settings April 15, 2026 11:10
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review is ineligible. To be eligible to request a review, you need a paid Copilot license, or your organization must enable Copilot code review.

Copilot AI review requested due to automatic review settings April 15, 2026 11:34
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review is ineligible. To be eligible to request a review, you need a paid Copilot license, or your organization must enable Copilot code review.

Copilot AI review requested due to automatic review settings April 15, 2026 11:46
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review is ineligible. To be eligible to request a review, you need a paid Copilot license, or your organization must enable Copilot code review.

Copilot AI review requested due to automatic review settings April 15, 2026 12:18
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review is ineligible. To be eligible to request a review, you need a paid Copilot license, or your organization must enable Copilot code review.

@sjbur
Copy link
Copy Markdown
Contributor

sjbur commented Apr 15, 2026

Day view Bug

  $('#scheduler').dxScheduler({
    timeZone: 'America/Los_Angeles',
    dataSource: data,
    views: ['day', 'week', 'workWeek', 'month', {
      type: 'day',
      name: 'myday',
      intervalCount: 7,
    }],
    hiddenWeekDays: [0, 1, 2, 3, 4, 5],
    currentView: 'myday',
    currentDate: new Date(2021, 3, 29),
    startDayHour: 9,
    height: 730,
  });

Actual result: all week days are visible

Expected result: hidden week days shouldn't be visible

Looks like we forgot about this case during the spec writing 😔

I think during chat with the PM the feature support for day view was more like 'nice to have' rather than 'must have'. But I looked at the code and it was rather easy to implement it. I tested, works fine. Added necessary tests.

Copilot AI review requested due to automatic review settings April 15, 2026 12:39
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review is ineligible. To be eligible to request a review, you need a paid Copilot license, or your organization must enable Copilot code review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants